//
//  LBFilter.mm
//  OpenGLGame
//
//  Created by Nguyen Cong Huy on 11/14/12.
//  Copyright (c) 2012 UIT. All rights reserved.
//

#include <iostream>
#include "LBFilter.h"
#include "LBProgram.h"
#include "LBTexture.h"
#include "LBGraphics.h"
#include "LBUtils.h"
#include "LBFramebuffer.h"

LBFilter::LBFilter(){
    texture = 0;
    program = 0;
    targetFilter = 0;
    fbo = 0;
    outputTexture = 0;
}

void LBFilter::init(char* vShaderStr, char* fShaderStr){
    LBGraphics* g = LBGraphics::getInstance();
    DELETE_SAFELY(program);
    
    if(vShaderStr == 0 && fShaderStr != 0){
        program = new LBProgram(g->getDefaultVShaderStr(), fShaderStr);
    }
    else if(vShaderStr != 0 && fShaderStr == 0){
        program = new LBProgram(vShaderStr, g->getDefaultFShaderStr());
    }
    else if(vShaderStr != 0 && fShaderStr != 0){
        program = new LBProgram(vShaderStr, fShaderStr);
    }
    else{
        program = new LBProgram(g->getDefaultVShaderStr(), g->getDefaultFShaderStr());
    }
    
    LBGraphics::getInstance()->useProgram(program);
    
    positionAttribute = program->attributeIndex("position");
    texCoorAttribute = program->attributeIndex("texCoor");
    textureUniform = program->uniformIndex("texture");
    mWorldUniform = program->uniformIndex("mWorld");
    mProjectionUniform = program->uniformIndex("mProjection");
    
    
    //NOTE:Data for 3 attribute and uniform above will set when call render()
    
    texture = 0;
    
    x = y = 0;
    scaleX = scaleY = 1.0f;
    targetFilter = 0;
}

void LBFilter::init(char* vShaderStr, char* fShaderStr, LBTexture* texture){
    init(vShaderStr, fShaderStr);
    this->texture = texture;
}

LBFilter::~LBFilter(){
    DELETE_SAFELY(program);
    DELETE_SAFELY(fbo);
    DELETE_SAFELY(outputTexture);
}

void LBFilter::render(){
    if(texture == 0){
        printf("Please setTexture() before\n");
        return;
    }
    
    LBGraphics* g = LBGraphics::getInstance();
    g->useProgram(program);
    fbo->beginRenderToTexture();
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    renderTexture(0, 0, 1.0f, 1.0f);
    if(targetFilter != 0) targetFilter->render();
}

void LBFilter::renderTexture(int x, int y, float scaleX, float scaleY){
    texture->setLocationAndScale(x, y, scaleX, scaleY);
    texture->setAngle(0.0f);
    texture->render();
}

void LBFilter::setTexture(LBTexture* texture){
    this->texture = texture;
    
    if(
       outputTexture == 0
       || (outputTexture != 0 && texture != 0 && (texture->getWidth() != outputTexture->getWidth() || texture->getHeight() != outputTexture->getHeight()))
       ){
        DELETE_SAFELY(outputTexture);
        outputTexture = new LBTexture(texture->getWidth(), texture->getHeight());
        DELETE_SAFELY(fbo);
        fbo = new LBFramebuffer(outputTexture);
        if(targetFilter != 0){
            targetFilter->setTexture(outputTexture);
        }
    }
}

void LBFilter::setLocationAndScale(float x, float y, float scaleX, float scaleY){
    this->x = x;
    this-> y = y;
    this->scaleX = scaleX;
    this->scaleY = scaleY;
    
    if(targetFilter != 0){
        targetFilter->setLocationAndScale(x, y, scaleX, scaleY);
    }
}

LBTexture* LBFilter::getTexture(){
    return texture;
}

LBFilter* LBFilter::addTarget(LBFilter* targetFilter){
    this->targetFilter = targetFilter;
    return targetFilter;
}

void LBFilter::addTargetToFinalTarget(LBFilter* targetFilter){
    if(this->targetFilter != 0) 
        this->targetFilter->addTargetToFinalTarget(targetFilter);
    else this->addTarget(targetFilter);
}
void LBFilter::untargetAll(){
    if(targetFilter != 0){
        targetFilter->untargetAll();
        targetFilter = 0;
    }
    else targetFilter = 0;
}

void LBFilter::setLocation(float x, float y){
    setLocationAndScale(x, y, 1.0f, 1.0f);
}

LBTexture* LBFilter::getOutputTexture(){
    return outputTexture;
}

LBTexture* LBFilter::getFinalOutputTexture(){
    if(targetFilter != 0)
        return targetFilter->getFinalOutputTexture();
    else return outputTexture;
}